/*
    Copyright(C) 2010 Ying-Chun Liu(PaulLiu). All rights reserved.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

package org.debian.paulliu.plft;

import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.awt.datatransfer.*;
import java.awt.image.*;
import java.applet.*;
import java.util.logging.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import org.apache.commons.codec.binary.Base64;

class PLFTWindow extends JApplet {

    private ResourceBundle resources = ResourceBundle.getBundle("PLFT");
    private JTextArea jtextarea_chat;
    private Logger logger = Logger.getLogger("PLFT");
    private JTextField jtextfield_chat;
    private JTextField jtextfield_LocalAddress;
    private JTextField jtextfield_RemoteAddress;
    private JButton jbutton_connect = null;
    private org.debian.paulliu.plft.Session session;
    private JFrame parentFrame = null;
    private Box eastBox = null;
    private Map<java.nio.ByteBuffer, ProgressWidget> progressBoxes=null;

    class MenuActionListener implements ActionListener {
	public void file_exit(ActionEvent e) {
            System.exit(0);
        }
	public void file_send(ActionEvent e) {
	    if (session == null || session.getFileChannel() == null) {
		return;
	    }
	    FileChannel fileChannel = session.getFileChannel();
	    JFileChooser fileChooser = new JFileChooser();
	    fileChooser.setMultiSelectionEnabled(false);
	    int result1 = fileChooser.showOpenDialog(PLFTWindow.this);
	    if (result1 == JFileChooser.APPROVE_OPTION) {
		PLFT.log(Level.INFO, "You choose to open this file: " +
			 fileChooser.getSelectedFile().getName());
		fileChannel.putFile(fileChooser.getSelectedFile());

	    }
	}
	public void options_local_address(ActionEvent e) {
	    JCheckBoxMenuItem jitem = (JCheckBoxMenuItem)e.getSource();
	    if (jitem.getState()) {
		jtextfield_LocalAddress.setText(session.getLocalAddressBase64());
	    } else {
		jtextfield_LocalAddress.setText(session.getLocalAddressBase64().substring(0,8));
	    }
	}
	/**
	 * event handler for menu
	 */
        public void actionPerformed(ActionEvent e) {
            String name = ((JMenuItem)e.getSource()).getText();
            if (name.compareTo(resources.getString("FILE_EXIT"))==0) {
                file_exit(e);
            } else if (name.compareTo(resources.getString("FILE_SEND"))==0) {
                file_send(e);
            } else if (name.compareTo(resources.getString("OPTIONS_LOCAL_ADDRESS"))==0) {
		options_local_address(e);
	    }
        }
    }

    class ConnectButtonActionListener implements ActionListener {
	/**
	 * event handler for "Connect" button
	 */
	public void actionPerformed(ActionEvent e) {
	    JButton jb;
	    jb = (JButton)e.getSource();
	    session.connect(jtextfield_RemoteAddress.getText());
	    if (session.getFileChannel() != null) {
		session.getFileChannel().addFileChannelEventListener(new FileChannelEventListener());
		jbutton_connect.setText(resources.getString("CONNECTED"));
		/* disable button and textfield actions */
		jbutton_connect.setEnabled(false);
		jtextfield_RemoteAddress.setEditable(false);
		KeyListener[] jtextfield_RemoteAddress_keyListeners = jtextfield_RemoteAddress.getKeyListeners();
		for (int i=0; i<jtextfield_RemoteAddress_keyListeners.length; i++) {
		    jtextfield_RemoteAddress.removeKeyListener(jtextfield_RemoteAddress_keyListeners[i]);
		}
		MouseListener[] jtextfield_RemoteAddress_mouseListeners = jtextfield_RemoteAddress.getMouseListeners();
		for (int i=0; i<jtextfield_RemoteAddress_mouseListeners.length; i++) {
		    jtextfield_RemoteAddress.removeMouseListener(jtextfield_RemoteAddress_mouseListeners[i]);
		}
	    }
	}
    }

    class ChatTextFieldActionListener implements ActionListener {
	/**
	 * event handler for chat TextField
	 */
	public void actionPerformed(ActionEvent e) {
	    JTextField jtf;
	    String newline = System.getProperty("line.separator");
	    jtf = (JTextField)e.getSource();

	    if (jtf.getText() == null || jtf.getText().length()==0) {
		return;
	    }
	    String message = "MESSAGE " + jtf.getText();
	    try {
		session.sendPacket(message.getBytes("UTF-8"));
	    } catch (Exception err) {
		PLFT.log(Level.SEVERE, err.toString());
	    }
	    jtextarea_chat.append(jtf.getText()+newline);
	    jtf.setText("");
	}
    }

    class RemoteAddressTextFieldListener implements KeyListener, MouseListener {
	JButton button_connect;
	public RemoteAddressTextFieldListener (JButton button_connect) {
	    this.button_connect = button_connect;
	}
	private void checkJTextFieldLength(JTextField jf) {
            if (jf.getText().length() == 8 && jf.isEditable()) {
                this.button_connect.setEnabled(true);
            } else if (jf.getText().length() == 16 && jf.isEditable()) {
		this.button_connect.setEnabled(true);
	    } else {
                this.button_connect.setEnabled(false);
            }
	}
	public void keyTyped(KeyEvent e) {
            JTextField jf=null;
            jf = (JTextField)e.getSource();
            checkJTextFieldLength(jf);
        }
        public void keyPressed(KeyEvent e) {
            keyTyped(e);
        }
        public void keyReleased(KeyEvent e) {
            keyTyped(e);
        }
        public void mouseClicked(MouseEvent e) {
            JTextField jf=null;
            jf = (JTextField)e.getSource();
            checkJTextFieldLength(jf);
        }
        public void mouseEntered(MouseEvent e) {
            mouseClicked(e);
        }
        public void mouseExited(MouseEvent e) {
            mouseClicked(e);
        }
        public void mousePressed(MouseEvent e) {
            mouseClicked(e);
        }
        public void mouseReleased(MouseEvent e) {
            mouseClicked(e);
        }
    }

    class RemoteSessionTextListener implements org.debian.paulliu.plft.SessionTextEventListener {
	private JTextArea jtextarea_chat;
	public RemoteSessionTextListener(JTextArea jtextarea_chat) {
	    this.jtextarea_chat = jtextarea_chat;
	}
	public void textReceived(SessionTextEvent e) {
	    String newline = System.getProperty("line.separator");
	    jtextarea_chat.append(">"+e.getText()+newline);
	}
    }

    class ProgressWidget extends Box {
	private JLabel filename;
	private JProgressBar progressbar;
	public ProgressWidget () {
	    super(BoxLayout.Y_AXIS);
	    filename = new JLabel();
	    progressbar = new JProgressBar(0,100);
	    this.add(filename);
	    this.add(progressbar);
	}
	public void setFilename(String filename) {
	    this.filename.setText(filename);
	}
	public void setProgress(int percentage) {
	    this.progressbar.setValue(percentage);
	}
    }

    class FileChannelEventListener implements org.debian.paulliu.plft.FileChannelEventListener {
	public void receivedFileChannelEvent(FileChannelEvent e) {
	    if (e.getType() == org.debian.paulliu.plft.FileChannelEvent.FileChannelEventType.PUT) {
		/* put event */
		java.awt.FileDialog fileDialog = new java.awt.FileDialog(parentFrame, "Save File", java.awt.FileDialog.SAVE);
		fileDialog.setFile(e.getLocalFile().getFile().getName());
		fileDialog.setVisible(true);
		if (fileDialog.getFile() == null) {
		    /* cancelled */
		    return;
		}
		org.debian.paulliu.plft.FileChannel fileChannel = session.getFileChannel();
		File outputFile = null;
		outputFile = new File(fileDialog.getDirectory(), fileDialog.getFile());
		fileChannel.getFile(e.getLocalFile(), outputFile);
	    } else if (e.getType() == org.debian.paulliu.plft.FileChannelEvent.FileChannelEventType.PROGRESS) {
		if (progressBoxes.containsKey(e.getLocalFile().getHash())) {
		    if (e.getProgress() >= e.getLocalFile().getLength()) {
			/* remove it */
			Box b = progressBoxes.get(e.getLocalFile().getHash());
			progressBoxes.remove(e.getLocalFile().getHash());
			eastBox.remove(b);
			eastBox.validate();
			getContentPane().validate();
		    } else {
			/* update it */
			ProgressWidget b = progressBoxes.get(e.getLocalFile().getHash());
			if (e.getLocalFile().getLength() > 0) {
			    long percentage = (e.getProgress()*100L)/(e.getLocalFile().getLength());
			    b.setProgress((int)percentage);
			}
		    }
		} else {
		    if (e.getProgress() < e.getLocalFile().getLength()) {
			/* add it */
			ProgressWidget b = new ProgressWidget();
			if (e.getLocalFile().getLength() > 0) {
			    long percentage = (e.getProgress()*100L)/(e.getLocalFile().getLength());
			    b.setProgress((int)percentage);
			}
			if (e.getLocalFile().getFile().getName() != null) {
			    b.setFilename(e.getLocalFile().getFile().getName());
			}
			progressBoxes.put(e.getLocalFile().getHash(),b);
			eastBox.add(b);
			eastBox.validate();
			getContentPane().validate();
		    }
		}
		
	    }

	}
    }

    /**
     * Create JMenu for this JApplet
     *
     * It will base on the data in mymenus and mymenuitems to create the
     *  menu bar
     */
    private void init_menu() {
	JMenu[] mymenus = {
	    new JMenu(resources.getString("FILE")),
	    new JMenu(resources.getString("OPTIONS"))
	};
	JMenuItem[][] mymenuitems = {
	    { new JMenuItem(resources.getString("FILE_SEND"))
	      , new JMenuItem(resources.getString("FILE_EXIT")) },
	    { new JCheckBoxMenuItem(resources.getString("OPTIONS_LOCAL_ADDRESS"), false) }
	};

	int i=0;
        int j=0;
        JMenuBar mb = null;
        MenuActionListener act = new MenuActionListener();
        for (i=0 ; i<mymenus.length; i++) {
            for (j=0; i<mymenuitems.length && j<mymenuitems[i].length; j++) {
                mymenus[i].add(mymenuitems[i][j]);
                mymenuitems[i][j].addActionListener(act);
            }
        }
        mb  = new JMenuBar();
        for (i=0 ; i<mymenus.length ; i++) {
            mb.add(mymenus[i]);
        }
        
        setJMenuBar(mb);
    }

    public void init() {

	init_menu();

	Container contentPane = getContentPane();
	contentPane.setLayout(new BorderLayout());

	Box box1 = Box.createVerticalBox();
	contentPane.add(BorderLayout.NORTH, box1); 

	Box box11 = Box.createHorizontalBox();
	box11.add(new JLabel(resources.getString("LOCALIP")));
	jtextfield_LocalAddress = new JTextField();
	jtextfield_LocalAddress.setText(session.getLocalAddressBase64().substring(0,8));
	jtextfield_LocalAddress.setEditable(false);
	box11.add(jtextfield_LocalAddress);
	box11.add(new JLabel(resources.getString("REMOTEIP")));
	jtextfield_RemoteAddress = new JTextField();
	box11.add(jtextfield_RemoteAddress);
	jbutton_connect = new JButton (resources.getString("CONNECT"));
	jbutton_connect.setEnabled(false);
	jbutton_connect.addActionListener(new ConnectButtonActionListener());
	RemoteAddressTextFieldListener jtextfield_RemoteAddress_listener = new RemoteAddressTextFieldListener(jbutton_connect);
	jtextfield_RemoteAddress.addKeyListener(jtextfield_RemoteAddress_listener);
	jtextfield_RemoteAddress.addMouseListener(jtextfield_RemoteAddress_listener);
	box11.add(jbutton_connect);
	box1.add(box11);

	JPanel panel2 = new JPanel(new BorderLayout());
	jtextarea_chat = new JTextArea();
	JScrollPane jscrollpane = new JScrollPane(jtextarea_chat);
	this.session.addSessionTextEventListener(new RemoteSessionTextListener(jtextarea_chat));
	panel2.add(BorderLayout.CENTER, jscrollpane);
	jtextfield_chat = new JTextField();
	jtextfield_chat.addActionListener(new ChatTextFieldActionListener());
	panel2.add(BorderLayout.SOUTH, jtextfield_chat);
	Box box2 = Box.createVerticalBox();
	box2.add(panel2);

	contentPane.add(BorderLayout.CENTER, box2);

	Box box3 = Box.createVerticalBox();
	contentPane.add(BorderLayout.SOUTH, box3);

	eastBox = Box.createVerticalBox();
	JScrollPane eastScrollPane =  new JScrollPane(eastBox);
	eastScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
	contentPane.add(BorderLayout.EAST, eastScrollPane);

	progressBoxes = new Hashtable<java.nio.ByteBuffer, ProgressWidget> ();
    }

    public void setParentFrame(JFrame frame) {
	this.parentFrame = frame;
    }

    public PLFTWindow(org.debian.paulliu.plft.Session session) {
	this.session= session;
    }

}
